package com.ai.service.made.impl;

import cn.hutool.core.util.StrUtil;
import com.ai.common.CommonResponse;
import com.ai.common.constant.enumP.PermissionType;
import com.ai.entity.made.MiningAreaRegionRelation;
import com.ai.entity.made.RegionBase;
import com.ai.entity.made.RegionManage;
import com.ai.entity.made.camera.CameraPO;
import com.ai.entity.made.page.RegionPage;
import com.ai.entity.security.SysPermission;
import com.ai.entity.security.SysRolePermissionRelation;
import com.ai.entity.security.SysUser;
import com.ai.mapper.RegionBaseMapper;
import com.ai.model.param.RegionInfoParam;
import com.ai.model.vo.RegionBaseVo;
import com.ai.model.vo.RegionVo;
import com.ai.service.made.*;
import com.ai.service.security.ISysPermissionService;
import com.ai.service.security.ISysRolePermissionRelationService;
import com.ai.service.security.ISysUserService;
import com.ai.util.SecurityUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.jsonwebtoken.lang.Collections;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 *
 * @author jiaok
 * @since 2023-07-24
 */
@Service
@Slf4j
public class RegionBaseServiceImpl extends ServiceImpl<RegionBaseMapper, RegionBase> implements IRegionBaseService {

    @Resource
    private ISysPermissionService iSysPermissionService;


    @Resource
    private IMiningAreaRegionRelationService iMiningAreaRegionRelationService;

    @Resource
    private ISysRolePermissionRelationService iSysRolePermissionRelationService;


    @Resource
    private IRegionManageService iRegionManageService;


    @Resource
    private IRegionBaseService iRegionBaseService;


    @Resource
    private ISysUserService iSysUserService;

    @Resource
    CameraService cameraService;

    /**
     * 获取所有的区域基本信息
     * @return
     */
    @Override
    public CommonResponse getList() {
        List<RegionBase> list =
                list();
        return CommonResponse.ok(list);
    }

    /**
     * 删除区域信息
     * @return
     */
    @Override
    @Transactional
    public CommonResponse deleteRegion(String id) {

        RegionBase regionBase = this.getById(id);
        
        //先删除对应的权限表中的数据
        SysPermission sysPermission = iSysPermissionService.getPermissionByCode(regionBase.getRegionCode());
        /**
         * 如果当前区域被其他角色所绑定，则不允许删除
         */
        List<SysRolePermissionRelation> list = iSysRolePermissionRelationService.list(new QueryWrapper<SysRolePermissionRelation>().eq("permission_id", sysPermission.getId()));

        if (!Collections.isEmpty(list)){
            return CommonResponse.error(501,"当前区域正在被使用，禁止删除");
        }
        //删除权限表中的数据
        iSysPermissionService.removeById(sysPermission);

        //获取当前组织下的所有组织id
        List<String> belowRegionIdList = iRegionBaseService.getBelowRegionIdList(id);
        long userCount = iSysUserService.count(new QueryWrapper<SysUser>().in("region_base_id", belowRegionIdList));
        if(userCount > 0){
            throw new RuntimeException("当前组织下存在用户信息，请解绑后重新删除");
        }
        long cameraCount = cameraService.count(new QueryWrapper<CameraPO>().in("region_id", belowRegionIdList));
        if (cameraCount > 0){
            throw new RuntimeException("当前组织下存在摄像头信息，请解绑后重新删除");
        }


        // : 2023-07-24 删除区域信息
        this.baseMapper.deleteById(id);
        //删除当前区域与摄像头之间的绑定关系
        iRegionManageService.removeRelationByRegionId(id);

        //

        return CommonResponse.ok();
    }


    @Override
    @Transactional
    public CommonResponse forceDelete(String id) {

        RegionBase regionBase = this.getById(id);

        //获取权限表中的数据
        SysPermission sysPermission = iSysPermissionService.getPermissionByCode(regionBase.getRegionCode());
        //查看所有的绑定关系
        List<SysRolePermissionRelation> bindList = iSysRolePermissionRelationService.list(new QueryWrapper<SysRolePermissionRelation>().eq("permission_id", sysPermission.getId()));

        //开始执行删除操作
        try {

            //删除权限
            iSysPermissionService.removeById(sysPermission.getId());
            //删除区域信息
            this.removeById(regionBase.getId());
            //删除与角色的绑定关系
            List<Integer> bindRoleIds = bindList.stream().map(SysRolePermissionRelation::getId).collect(Collectors.toList());
            iSysRolePermissionRelationService.removeBatchByIds(bindRoleIds);
            //删除摄像头绑定关系
            iRegionManageService.removeRelationByRegionId(id);

        }catch (Exception e){
            throw new RuntimeException("删除区域信息失败");
        }


        return CommonResponse.ok("删除成功");
    }

    @Override
    public List<String> getManageCamera(List<RegionVo> coalMineVoRegions) {

        List<Integer> regionIds = coalMineVoRegions.stream().map(RegionVo::getRegionId).collect(Collectors.toList());
        List<RegionManage> regionManageList = iRegionManageService.list(new QueryWrapper<RegionManage>().select("camera_id").in("region_id", regionIds));
        if (CollectionUtils.isEmpty(regionManageList)){
            return null;
        }
        List<String> manageCameraIdList = regionManageList.stream().map(RegionManage::getCameraId).collect(Collectors.toList());
        List<String> manageCameraCodeList =  cameraService.getCameraCodeList(manageCameraIdList);


        return manageCameraCodeList;
    }

    @Override
    public List<RegionBase> getBelowRegionList() {
        //当前登录用户所属组织
        String loginRegionBaseId = SecurityUtils.getLoginRegionBaseId();
        List<RegionBase> resList = new ArrayList<>();
        return fetchRegionAndChildren(Integer.valueOf(loginRegionBaseId), resList);
    }

    @Override
    public List<String> getBelowRegionIdList(String loginRegionBaseId) {
        List<RegionBase> resList = new ArrayList<>();
        List<RegionBase> fetchRegionAndChildrenList = fetchRegionAndChildren(Integer.valueOf(loginRegionBaseId), resList);
        return fetchRegionAndChildrenList.stream().map(regionBase -> String.valueOf(regionBase.getId())).collect(Collectors.toList());
    }


    public List<Map<String, Object>> getTreeBelowRegionList(){
      return   fetchTreeBelowRegionList(Integer.valueOf(SecurityUtils.getLoginRegionBaseId()));
    }


    /**
     * 递归获取当前组及其子组织
     * @param fatherId 父组织id
     * @return
     */
    public List<Map<String, Object>> fetchTreeBelowRegionList(Integer fatherId){

        List<Map<String, Object>> result = new ArrayList<>();

        // 查询当前父节点的直接子节点
        List<RegionBase> regionBaseList = list(new QueryWrapper<RegionBase>().eq("father_id", fatherId));

        // 遍历当前节点的子节点
        for (RegionBase region : regionBaseList) {
            // 封装当前节点数据
            Map<String, Object> node = new HashMap<>();
            node.put("id", region.getId());
            node.put("label", region.getRegionName());

            // 优化：递归查询子节点并封装为 children
            node.put("children", fetchTreeBelowRegionList(region.getId()));

            result.add(node);
        }

        return result;
    }


    /**
     * 递归获取当前组及其子组织
     * @param fatherId 父组织id
     * @param resList  组织列表
     * @return
     */
    public List<RegionBase> fetchRegionAndChildren(Integer fatherId, List<RegionBase> resList){

        // 查询当前父节点
        List<RegionBase> parentRegion = list(new QueryWrapper<RegionBase>().eq("id", fatherId));
        resList.addAll(parentRegion);

        // 查询所有子节点
        List<RegionBase> childRegions = list(new QueryWrapper<RegionBase>().eq("father_id", fatherId));

        // 对每个子节点递归查询
        for (RegionBase region : childRegions) {
            fetchRegionAndChildren(region.getId(), resList);
        }

        return resList;
    }

    /**
     * 新增区域信息
     * 新增的同时，在权限表中也要新增
     * @param regionBaseVo
     * @return
     */
    @Override
    @Transactional
    public CommonResponse add(RegionBaseVo regionBaseVo) {

        SecurityContext context = SecurityContextHolder.getContext();
        Authentication authentication = context.getAuthentication();

        //  2024-06-11 自动生成区域code，用于权限部分 连接基础信息和对应权限部分的钩子
        if (StringUtils.isBlank(regionBaseVo.getRegionCode())){
            regionBaseVo.setRegionCode(UUID.randomUUID().toString().replace("-", ""));
        }

        //区域代码不能重复
        RegionBase db=getRegionBaseByCode(regionBaseVo.getRegionCode());
        if (db != null){
            return CommonResponse.error("当前区域代码已存在");
        }

        /**
         * 抽离出权限部分所需要的内容
         */
        SysPermission sysPermission = new SysPermission();
        sysPermission.setPermissionCode(regionBaseVo.getRegionCode());
        sysPermission.setPermissionName(regionBaseVo.getRegionName());
        sysPermission.setPermissionType(PermissionType.REGION_PERMISSION.getType());
        boolean save = iSysPermissionService.save(sysPermission);
        if (!save){
            log.info("===========================  区域信息提取至权限表失败  ===========================");
            return CommonResponse.error("保存失败，请重新尝试操作");
        }

        String userName = SecurityUtils.getLoginUserName();

        RegionBase regionBase = new RegionBase();
        regionBase.setRegionCode(regionBaseVo.getRegionCode());
        regionBase.setRegionName(regionBaseVo.getRegionName());
        regionBase.setPhone(regionBaseVo.getPhone());
        regionBase.setResponsibility(regionBaseVo.getResponsibility());
        regionBase.setCreateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        regionBase.setUpdateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        regionBase.setCreateUser(userName);
        regionBase.setUpdateUser(userName);
        if (StrUtil.isNotEmpty(regionBaseVo.getFatherId())){
            //传入区域父级id
            regionBase.setFatherId(regionBaseVo.getFatherId());
        }else {
            regionBase.setFatherId(SecurityUtils.getLoginRegionBaseId());
        }


        //保存区域信息
        int insert = this.baseMapper.insert(regionBase);
        if (insert != 1){
            log.info("===========================  区域信息保存失败  ===========================");
            return CommonResponse.error("保存失败，请重新尝试操作");
        }

        //处理一级 二级区域关系
        MiningAreaRegionRelation miningAreaRegionRelation = new MiningAreaRegionRelation();
        miningAreaRegionRelation.setRegionId(regionBase.getId());
        miningAreaRegionRelation.setMiningAreaId(Integer.valueOf(regionBaseVo.getFirstLevId()));
        miningAreaRegionRelation.setCreateTime(LocalDateTime.now());
        miningAreaRegionRelation.setCreateUser(SecurityUtils.getLoginUserName());
        miningAreaRegionRelation.setUpdateUser(SecurityUtils.getLoginUserName());
        miningAreaRegionRelation.setUpdateTime(LocalDateTime.now());

        iMiningAreaRegionRelationService.save(miningAreaRegionRelation);

        return CommonResponse.ok();
    }

    /**
     * 根据区域code查询该区域是否存在
     * @param regionCode
     * @return
     */
    @Override
    public RegionBase getRegionBaseByCode(String regionCode) {

        return this.getOne(new QueryWrapper<RegionBase>().eq("region_code", regionCode));

    }

    /**
     * 区域分页查询
     * @param pageParam
     * @return
     */
    @Override
    public IPage<RegionBase> getPage(RegionPage pageParam) {

        QueryWrapper<RegionBase> wrapper = pageParam.getQuery(new QueryWrapper<>());

        RegionPage page = this.page(pageParam, wrapper);

        return page;
    }

    /**
     * 通过id获取指定的区域信息
     * @param id
     * @return
     */
    @Override
    public CommonResponse getAppoint(String id) {
        RegionBase regionBase = getById(id);
        if ( regionBase != null ){
            return CommonResponse.ok(regionBase);
        }
        return CommonResponse.error("数据不存在");
    }

    /**
     * 更新区域信息
     * @param regionBase
     * @return
     */
    @Override
    @Transactional
    public CommonResponse updateRegion(RegionBase regionBase) {

        //首先获取DB中的该行数据
        RegionBase dbBase = this.getById(regionBase.getId());
        String oldRegionCode = dbBase.getRegionCode();

        //查询权限表中对应的数据
        SysPermission permission=  iSysPermissionService.getPermissionByCode(oldRegionCode);

        if (permission == null){
            log.info("===========================  区域对应的权限信息不存在  ===========================");
            return CommonResponse.error("修改失败");
        }

        //更新区域信息数据、权限数据
        boolean b = this.updateById(regionBase);
        if (!b){
            log.info("===========================  修改区域信息失败 ===========================");
            throw new RuntimeException("修改区域信息失败");
//            return CommonResponse.error("修改失败");
        }


        permission.setPermissionCode(regionBase.getRegionCode());
        permission.setPermissionName(regionBase.getRegionName());
        permission.setPermissionType(PermissionType.REGION_PERMISSION.getType());
        boolean b1 = iSysPermissionService.updateById(permission);
        if (!b1){
            log.info("===========================  修改权限信息失败 ===========================");
            throw new RuntimeException("修改权限信息失败");
//            return CommonResponse.error("修改失败");
        }

        return CommonResponse.ok("区域信息更新成功");
    }

    @Override
    public RegionBase getRegionByCameraId(Integer cameraId) {

        RegionBase regionBase =  this.baseMapper.getRegionByCameraId(cameraId);


        return regionBase;
    }

    @Override
    public boolean saveOrUpdateRegionInfo(RegionInfoParam regionInfoParam) {
        RegionBase regionBase = getById(regionInfoParam.getRegionId());
        regionBase.setRegionName(regionInfoParam.getRegionName());
        regionBase.setRegionCode(regionInfoParam.getRegionCode());
        regionBase.setResponsibility(regionInfoParam.getResponsibility());
        regionBase.setPhone(regionInfoParam.getPhone());
        return  this.saveOrUpdate(regionBase);
    }


}
